package org.sqldroid;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.SQLWarning;
import java.sql.Statement;

import android.database.Cursor;
import android.util.Log;

public class SqldroidStatement implements Statement {

    private SQLiteDatabase     db;
    private SqldroidConnection sqldroidConnection;
    private SqldroidResultSet        rs      = null;
    private Integer                  maxRows = null;

    public SqldroidStatement(SqldroidConnection sqldroid) {
        this.sqldroidConnection = sqldroid;
        this.db = sqldroid.getDb();
    }

    @Override
    public void addBatch(String sql) throws SQLException {
        System.err.println(" ********************* not implemented @ " + DebugPrinter.getFileName() + " line "
                + DebugPrinter.getLineNumber());

    }

    @Override
    public void cancel() throws SQLException {
        System.err.println(" ********************* not implemented @ " + DebugPrinter.getFileName() + " line "
                + DebugPrinter.getLineNumber());

    }

    @Override
    public void clearBatch() throws SQLException {
        System.err.println(" ********************* not implemented @ " + DebugPrinter.getFileName() + " line "
                + DebugPrinter.getLineNumber());

    }

    @Override
    public void clearWarnings() throws SQLException {
        System.err.println(" ********************* not implemented @ " + DebugPrinter.getFileName() + " line "
                + DebugPrinter.getLineNumber());

    }

    @Override
    public void close() throws SQLException {
        closeResultSet();
        sqldroidConnection = null;
        db = null;
    }

    private void closeResultSet() throws SQLException {
        if (rs != null) {
            rs.close();
            rs = null;
        }
    }

    @Override
    public boolean execute(String sql) throws SQLException {
        boolean ok = false;
        closeResultSet();
        try {
            boolean isSelect = sql.toUpperCase().matches("(?m)(?s)\\s*SELECT.*");
            if (isSelect) {
                String limitedSql = sql + (maxRows != null ? " LIMIT " + maxRows : "");
                rs = new SqldroidResultSet(db.rawQuery(limitedSql, new String[0]));
            } else {
                db.execSQL(sql);
            }
            ok = true;

            boolean resultSetAvailable = ok && !sql.toUpperCase().startsWith("CREATE") && rs != null
                    && rs.getMetaData().getColumnCount() != 0;

            if (resultSetAvailable) {
                boolean headerDrawn = false;
                while (rs.next()) {
                    if (!headerDrawn) {
                        Log.d("SqlDroid", sql);
                        for (int i = 1; i <= rs.getMetaData().getColumnCount(); i++) {
                            System.out.print(" | ");
                            System.out.print(rs.getMetaData().getColumnLabel(i));
                        }
                        System.out.println(" | ");
                        headerDrawn = true;
                    }
                    for (int i = 1; i <= rs.getMetaData().getColumnCount(); i++) {
                        System.out.print(" | ");
                        System.out.print(rs.getString(i));
                    }
                    System.out.println(" | ");
                }
                rs.beforeFirst();
            }

            return resultSetAvailable;
        } catch (android.database.SQLException e) {
            Log.e("Sqldroid", "SQLException: '" + e.getClass().getName() + "' '" + e.getMessage() + "'");
            e.printStackTrace();
            throw e;
        } catch (java.lang.RuntimeException e) {
            Log.e("Sqldroid", "RuntimeException: '" + e.getClass().getName() + "' '" + e.getMessage() + "'");
            e.printStackTrace();
            throw e;
        } catch (Error e) {
            Log.e("Sqldroid", "Error: '" + e.getClass().getName() + "' '" + e.getMessage() + "'");
            e.printStackTrace();
            throw e;
        }
    }

    @Override
    public boolean execute(String sql, int autoGeneratedKeys) throws SQLException {
        System.err.println(" ********************* not implemented @ " + DebugPrinter.getFileName() + " line "
                + DebugPrinter.getLineNumber());

        return false;
    }

    @Override
    public boolean execute(String sql, int[] columnIndexes) throws SQLException {
        System.err.println(" ********************* not implemented @ " + DebugPrinter.getFileName() + " line "
                + DebugPrinter.getLineNumber());

        return false;
    }

    @Override
    public boolean execute(String sql, String[] columnNames) throws SQLException {
        System.err.println(" ********************* not implemented @ " + DebugPrinter.getFileName() + " line "
                + DebugPrinter.getLineNumber());

        return false;
    }

    @Override
    public int[] executeBatch() throws SQLException {
        System.err.println(" ********************* not implemented @ " + DebugPrinter.getFileName() + " line "
                + DebugPrinter.getLineNumber());
        return null;
    }

    @Override
    public ResultSet executeQuery(String sql) throws SQLException {
        closeResultSet();
        Cursor c = db.rawQuery(sql, null);
        rs = new SqldroidResultSet(c);
        return rs;
    }

    @Override
    public int executeUpdate(String sql) throws SQLException {
        closeResultSet();
        db.execSQL(sql);
        return 0;
    }

    @Override
    public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException {
        System.err.println(" ********************* not implemented @ " + DebugPrinter.getFileName() + " line "
                + DebugPrinter.getLineNumber());
        return 0;
    }

    @Override
    public int executeUpdate(String sql, int[] columnIndexes) throws SQLException {
        System.err.println(" ********************* not implemented @ " + DebugPrinter.getFileName() + " line "
                + DebugPrinter.getLineNumber());
        return 0;
    }

    @Override
    public int executeUpdate(String sql, String[] columnNames) throws SQLException {
        System.err.println(" ********************* not implemented @ " + DebugPrinter.getFileName() + " line "
                + DebugPrinter.getLineNumber());
        return 0;
    }

    @Override
    public Connection getConnection() throws SQLException {
        return sqldroidConnection;
    }

    @Override
    public int getFetchDirection() throws SQLException {
        System.err.println(" ********************* not implemented @ " + DebugPrinter.getFileName() + " line "
                + DebugPrinter.getLineNumber());
        return 0;
    }

    @Override
    public int getFetchSize() throws SQLException {
        System.err.println(" ********************* not implemented @ " + DebugPrinter.getFileName() + " line "
                + DebugPrinter.getLineNumber());
        return 0;
    }

    @Override
    public ResultSet getGeneratedKeys() throws SQLException {
        System.err.println(" ********************* not implemented @ " + DebugPrinter.getFileName() + " line "
                + DebugPrinter.getLineNumber());
        return null;
    }

    @Override
    public int getMaxFieldSize() throws SQLException {
        System.err.println(" ********************* not implemented @ " + DebugPrinter.getFileName() + " line "
                + DebugPrinter.getLineNumber());
        return 0;
    }

    @Override
    public int getMaxRows() throws SQLException {
        System.err.println(" ********************* not implemented @ " + DebugPrinter.getFileName() + " line "
                + DebugPrinter.getLineNumber());
        return 0;
    }

    @Override
    public boolean getMoreResults() throws SQLException {
        return getMoreResults(CLOSE_CURRENT_RESULT);
    }

    @Override
    public boolean getMoreResults(int current) throws SQLException {
        closeResultSet();
        return false;
    }

    @Override
    public int getQueryTimeout() throws SQLException {
        System.err.println(" ********************* not implemented @ " + DebugPrinter.getFileName() + " line "
                + DebugPrinter.getLineNumber());
        return 0;
    }

    @Override
    public ResultSet getResultSet() throws SQLException {
        return rs;
    }

    @Override
    public int getResultSetConcurrency() throws SQLException {
        System.err.println(" ********************* not implemented @ " + DebugPrinter.getFileName() + " line "
                + DebugPrinter.getLineNumber());
        return 0;
    }

    @Override
    public int getResultSetHoldability() throws SQLException {
        System.err.println(" ********************* not implemented @ " + DebugPrinter.getFileName() + " line "
                + DebugPrinter.getLineNumber());
        return 0;
    }

    @Override
    public int getResultSetType() throws SQLException {
        System.err.println(" ********************* not implemented @ " + DebugPrinter.getFileName() + " line "
                + DebugPrinter.getLineNumber());
        return 0;
    }

    @Override
    public int getUpdateCount() throws SQLException {
        System.err.println(" ********************* not implemented @ " + DebugPrinter.getFileName() + " line "
                + DebugPrinter.getLineNumber());
        return 0;
    }

    @Override
    public SQLWarning getWarnings() throws SQLException {
        System.err.println(" ********************* not implemented @ " + DebugPrinter.getFileName() + " line "
                + DebugPrinter.getLineNumber());
        return null;
    }

    @Override
    public void setCursorName(String name) throws SQLException {
        System.err.println(" ********************* not implemented @ " + DebugPrinter.getFileName() + " line "
                + DebugPrinter.getLineNumber());

    }

    @Override
    public void setEscapeProcessing(boolean enable) throws SQLException {
        System.err.println(" ********************* not implemented @ " + DebugPrinter.getFileName() + " line "
                + DebugPrinter.getLineNumber());

    }

    @Override
    public void setFetchDirection(int direction) throws SQLException {
        System.err.println(" ********************* not implemented @ " + DebugPrinter.getFileName() + " line "
                + DebugPrinter.getLineNumber());

    }

    @Override
    public void setFetchSize(int rows) throws SQLException {
        System.err.println(" ********************* not implemented @ " + DebugPrinter.getFileName() + " line "
                + DebugPrinter.getLineNumber());
    }

    @Override
    public void setMaxFieldSize(int max) throws SQLException {
        System.err.println(" ********************* not implemented @ " + DebugPrinter.getFileName() + " line "
                + DebugPrinter.getLineNumber());
    }

    @Override
    public void setMaxRows(int max) throws SQLException {
        if (isClosed()) {
            throw new SQLException("Statement is closed.");
        } else if (max < 0) {
            throw new SQLException("Max rows must be zero or positive. Got " + max);
        } else if (max == 0) {
            maxRows = null;
        } else {
            maxRows = max;
        }
    }

    @Override
    public void setQueryTimeout(int seconds) throws SQLException {
        System.err.println(" ********************* not implemented @ " + DebugPrinter.getFileName() + " line "
                + DebugPrinter.getLineNumber());
    }

    @Override
    public boolean isWrapperFor(Class<?> arg0) throws SQLException {
        System.err.println(" ********************* not implemented @ " + DebugPrinter.getFileName() + " line "
                + DebugPrinter.getLineNumber());
        return false;
    }

    @Override
    public <T> T unwrap(Class<T> arg0) throws SQLException {
        System.err.println(" ********************* not implemented @ " + DebugPrinter.getFileName() + " line "
                + DebugPrinter.getLineNumber());
        return null;
    }

    @Override
    public boolean isClosed() throws SQLException {
        return sqldroidConnection == null;
    }

    @Override
    public boolean isPoolable() throws SQLException {
        System.err.println(" ********************* not implemented @ " + DebugPrinter.getFileName() + " line "
                + DebugPrinter.getLineNumber());
        return false;
    }

    @Override
    public void setPoolable(boolean poolable) throws SQLException {
        System.err.println(" ********************* not implemented @ " + DebugPrinter.getFileName() + " line "
                + DebugPrinter.getLineNumber());

    }

}
